#include "..\bhttpclient\request.h"
#include "..\bhttpclient\request.h"
#include "uis_request.h"
#include <chrono>
#ifdef _WIN32
#include <objbase.h> // guid
#endif
#include "bbase64.h"
#include "bhmacsha1.h"

using namespace uis;

#define HTTP_KEY_PREFIX "TESTS "
#define HTTP_KEY_ID "12345678909876543210"
#define HTTP_KEY_SECRET "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

// Key
#define HEADER_ACCEPT           "Accept"           //浏览器可接受的MIME类型
#define HEADER_ACCEPT_ENCODING  "Accept-Encoding"  //数据编码方式
#define HEADER_ACCEPT_LANGUAGE  "Accept-Language"  //语言种类
#define HEADER_AUTHORIZATION    "Authorization"    //签名
#define HEADER_SIGN_DATE        "Sign-Date"        //消息发起的时间戳
#define HEADER_MSG_IDENT        "Msg-Ident"        //消息唯一标识
#define HEADER_CONTENT_TYPE     "Content-Type"     //说明了请求主体的内容是如何编码

// Value
#define HEADER_ACCEPT_VALUE           "*/*"
#define HEADER_ACCEPT_ENCODING_VALUE  "deflate"//"gzip, deflate"
#define HEADER_ACCEPT_LANGUAGE_VALUE  "zh-CN"

#define TAB_ITEM "\n"
#define HTTP_METHOD_POST_STR	"POST"
#define HTTP_METHOD_PUT_STR		"PUT"
#define HTTP_METHOD_GET_STR		"GET"
#define HTTP_METHOD_DELETE_STR	"DELETE"

request::request(bhttp::brequest::type tp, const std::string& content_type)
{
    method(tp);
    header(HEADER_ACCEPT, HEADER_ACCEPT_VALUE);
    header(HEADER_ACCEPT_ENCODING, HEADER_ACCEPT_ENCODING_VALUE);
    header(HEADER_ACCEPT_LANGUAGE, HEADER_ACCEPT_LANGUAGE_VALUE);
    header(HEADER_CONTENT_TYPE, content_type);
    header(HEADER_MSG_IDENT, make_msg_ident());
    make_auth();
}

request::~request()
{
}

void uis::request::make_auth()
{
    header(HEADER_SIGN_DATE, make_sign_date());
    header(HEADER_SIGN_DATE, make_sign_date());
    std::string strmethod;
    switch (method())
    {
    case brequest::type::GET: strmethod = HTTP_METHOD_GET_STR; break;
    case brequest::type::POST: strmethod = HTTP_METHOD_POST_STR; break;
    case brequest::type::DEL: strmethod = HTTP_METHOD_DELETE_STR; break;
    case brequest::type::PUT: strmethod = HTTP_METHOD_PUT_STR; break;
    default: break;
    }
    std::string str;
    str.append(strmethod).append(TAB_ITEM)
        .append(header(HEADER_CONTENT_TYPE)).append(TAB_ITEM)
        .append(header(HEADER_SIGN_DATE)).append(TAB_ITEM)
        .append(header(HEADER_MSG_IDENT));

    std::string digest = butils::hmacsha1(HTTP_KEY_SECRET, str);
    std::string signature = butils::base64::encode(digest);
    std::string authorization(HTTP_KEY_PREFIX);
    authorization.append(HTTP_KEY_ID).append(":").append(signature);
    header(HEADER_AUTHORIZATION, authorization);
}

std::string uis::request::make_msg_ident()
{
    char buf[64] = { 0 };
    GUID guid;
    if (S_OK == ::CoCreateGuid(&guid))
    {
        sprintf_s(buf, sizeof(buf)
            , "%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X"
            , guid.Data1
            , guid.Data2
            , guid.Data3
            , guid.Data4[0], guid.Data4[1]
            , guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5]
            , guid.Data4[6], guid.Data4[7]
        );
    }
    return std::string(buf);
}

std::string uis::request::make_sign_date()
{
    const auto& now = std::chrono::system_clock::now();
    return std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count());
}
